#include "kb.h"

#include "bt.h"
#include "oled.h"

#undef Handler
#define Handler Kb_HandleTypeDef*

#undef handler
#define handler (**(Kb_HandleTypeDef**)&handle)

const char* keyboard =
    "`1234567890-= B\0T qwertyuiop[]\\\0C asdfghjkl;' E\0S zxcvbnm,./ SP\0"
    "~!@#$%^&*()_+ B\0T QWERTYUIOP{}|\0C ASDFGHJKL:\" E\0S ZXCVBNM<>? SP";

void Kb_Init(void* handle, const char* str) {
  Bt_Init(Kb_M_L, NULL, NULL, Kb_M_O,    // M
          Kb_U_LJ, NULL, Kb_U_LJ, NULL,  // U
          Kb_D_LJ, NULL, Kb_D_LJ, NULL,  // D
          Kb_L_LJ, NULL, Kb_L_LJ, NULL,  // L
          Kb_R_LJ, NULL, Kb_R_LJ, NULL,  // R
          100);
  handler.outo = 0;
  handler.save = 0;
  handler.letter = 0;
  handler.capsLK = 0;
  handler.shift = 0;
  handler.ifShowCursor = 1;
  handler.timeShowCursor = 0;
  uint8_t i = 0;
  while (str[i] != '\0' && i < 16) {
    handler.str[i] = str[i];
    i++;
  }
  handler.cursor = i;
  while (i < 16) {
    handler.str[i] = '\0';
    i++;
  }
  Kb_InitShow(handle);
  Kb_ShowStr(handle);
  turn = 0xFF;
  Kb_ShowLetter(handle);
  turn = 0x00;
  while (hbt.bu & BU_M) Bt_Update();
}
void Kb_InitShow(void* handle) {
  Oled_ClearAll();
  Oled_ShowStringBig(0, 0, "  ");
  for (uint8_t i = 0; i < 24; i++) {
    Oled_ShowCharSmall(i * 6, 2, 0x80);
    Oled_ShowCharSmall(i * 6, 7, 0x80);
  }
  for (uint8_t j = 3; j < 8; j++) {
    Oled_ShowStringSmall(116, j, "\x7F\x7F\x7F\x7F");
  }

  Kb_ShowBoard(handle);
}
void Kb_Run(void* handle) {
  while (1) {
    Bt_Update();
    Bt_Run(handle);
    Kb_ShowCursor(handle);
    if (handler.outo) {
      return;
    }
  }
}

void Kb_ShowKeyboard(void) {
  Oled_ShowStringSmall(19, 3, keyboard);
  Oled_ShowStringSmall(19, 4, keyboard + 16);
  Oled_ShowStringSmall(19, 5, keyboard + 32);
  Oled_ShowStringSmall(19, 6, keyboard + 48);
}
void Kb_ShowCapboard(void) {
  Oled_ShowStringSmall(19, 3, keyboard + 64);
  Oled_ShowStringSmall(19, 4, keyboard + 80);
  Oled_ShowStringSmall(19, 5, keyboard + 96);
  Oled_ShowStringSmall(19, 6, keyboard + 112);
}
void Kb_ShowBoard(void* handle) {
  if (handler.capsLK ^ handler.shift) {
    Oled_ShowStringSmall(19, 3, keyboard + 64);
    Oled_ShowStringSmall(19, 4, keyboard + 80);
    Oled_ShowStringSmall(19, 5, keyboard + 96);
    Oled_ShowStringSmall(19, 6, keyboard + 112);
  } else {
    Oled_ShowStringSmall(19, 3, keyboard);
    Oled_ShowStringSmall(19, 4, keyboard + 16);
    Oled_ShowStringSmall(19, 5, keyboard + 32);
    Oled_ShowStringSmall(19, 6, keyboard + 48);
  }
  if (handler.capsLK) {
    Oled_ShowCharSmall(13, 5, '\x7F');
  } else {
    Oled_ShowCharSmall(13, 5, ' ');
  }
  if (handler.shift) {
    Oled_ShowCharSmall(13, 6, '\x7F');
  } else {
    Oled_ShowCharSmall(13, 6, ' ');
  }
}
void Kb_ShowLetter(void* handle) {
  switch (handler.letter) {
    case 13:
      // Backspace
      Oled_ShowCharSmall(97, 3, ' ');
      Oled_ShowCharSmall(103, 3, 'B');
      break;
    case 16:
      // Tab
      Oled_ShowCharSmall(19, 4, 'T');
      Oled_ShowCharSmall(25, 4, ' ');
      break;
    case 32:
      // CapsLK
      Oled_ShowCharSmall(19, 5, 'C');
      Oled_ShowCharSmall(25, 5, ' ');
      break;
    case 45:
      // Enter
      Oled_ShowCharSmall(97, 5, ' ');
      Oled_ShowCharSmall(103, 5, 'E');
      break;
    case 48:
      // Shift
      Oled_ShowCharSmall(19, 6, 'S');
      Oled_ShowCharSmall(25, 6, ' ');
      break;
    case 60:
      // Space
      Oled_ShowCharSmall(91, 6, ' ');
      Oled_ShowCharSmall(97, 6, 'S');
      Oled_ShowCharSmall(103, 6, 'P');
      break;
    case 63:
      break;
    default:
      Oled_ShowCharSmall(
          19 + (handler.letter % 16) * 6, 3 + handler.letter / 16,
          keyboard[handler.letter + 64 * (handler.capsLK ^ handler.shift)]);
      break;
  }
}
void Kb_ShowCursor(void* handle) {
  if (handler.timeShowCursor + 900 < hbt.time.now) {
    Oled_ShowCharBig(handler.cursor * 8, 0, handler.ifShowCursor ? 0x81 : ' ');
    handler.timeShowCursor = hbt.time.now;
    handler.ifShowCursor = ~handler.ifShowCursor;
  }
}
void Kb_ShowStr(void* handle) {
  Oled_ShowStringBig(0, 0, (char*)handler.str);
  handler.timeShowCursor = 0;
  handler.ifShowCursor = 1;
}

void Kb_M_L(void* handle) { handler.outo = 1; }
void Kb_M_O(void* handle) {
  if (handler.letter == 13) {
    // Backspace
    Oled_ShowCharBig(handler.cursor * 8, 0, ' ');
    if (handler.cursor > 0) handler.cursor--;
    handler.str[handler.cursor] = '\0';
  } else if (handler.letter == 16) {
    // Tab
    if (handler.cursor > 13) {
      // 编辑栏已满, 无法插入新的Tab
      return;
    }
    handler.str[handler.cursor] = ' ';
    handler.cursor++;
    handler.str[handler.cursor] = ' ';
    handler.cursor++;
  } else if (handler.letter == 45) {
    // Enter
    handler.outo = 1;
    handler.save = 1;
    return;
  } else if (handler.cursor > 14) {
    // 编辑栏已满, 无法插入新的字符
    return;
  } else if (handler.letter == 32) {
    // CapsLK
    handler.capsLK = !handler.capsLK;
    Kb_ShowBoard(handle);
    turn = 0xFF;
    Kb_ShowLetter(handle);
    turn = 0x00;
    return;
  } else if (handler.letter == 48) {
    // Shift
    handler.shift = !handler.shift;
    Kb_ShowBoard(handle);
    turn = 0xFF;
    Kb_ShowLetter(handle);
    turn = 0x00;
    return;
  } else if (handler.letter == 60) {
    // Space
    handler.str[handler.cursor] = ' ';
    handler.cursor++;
  } else {
    handler.str[handler.cursor] =
        keyboard[handler.letter + ((handler.capsLK ^ handler.shift) << 6)];
    handler.cursor++;
  }
  Kb_ShowStr(handle);
  if (handler.shift) {
    handler.shift = 0;
    Kb_ShowBoard(handle);
    turn = 0xFF;
    Kb_ShowLetter(handle);
    turn = 0x00;
  }
}
void Kb_U_LJ(void* handle) {
  if (handler.letter < 14) return;
  Kb_ShowLetter(handle);
  if (handler.letter == 30) {
    handler.letter = 13;
  } else {
    handler.letter -= 16;
  }
  turn = 0xFF;
  Kb_ShowLetter(handle);
  turn = 0x00;
}
void Kb_D_LJ(void* handle) {
  Kb_ShowLetter(handle);
  if (handler.letter == 1) {
    handler.letter = 16;
  } else if (handler.letter == 30) {
    handler.letter = 45;
  } else if (handler.letter == 45) {
    handler.letter = 60;
  } else if (handler.letter < 46) {
    handler.letter += 16;
  } else {
    handler.letter -= 48;
  }
  turn = 0xFF;
  Kb_ShowLetter(handle);
  turn = 0x00;
}
void Kb_L_LJ(void* handle) {
  Kb_ShowLetter(handle);
  if (handler.letter == 0) {
    handler.letter = 13;
  } else if (handler.letter == 16) {
    handler.letter = 30;
  } else if (handler.letter == 18) {
    handler.letter = 16;
  } else if (handler.letter == 32) {
    handler.letter = 45;
  } else if (handler.letter == 34) {
    handler.letter = 32;
  } else if (handler.letter == 48) {
    handler.letter = 60;
  } else if (handler.letter == 50) {
    handler.letter = 48;
  } else {
    handler.letter--;
  }
  turn = 0xFF;
  Kb_ShowLetter(handle);
  turn = 0x00;
}
void Kb_R_LJ(void* handle) {
  Kb_ShowLetter(handle);
  if (handler.letter == 13) {
    handler.letter = 0;
  } else if (handler.letter == 16) {
    handler.letter = 18;
  } else if (handler.letter == 30) {
    handler.letter = 16;
  } else if (handler.letter == 32) {
    handler.letter = 34;
  } else if (handler.letter == 45) {
    handler.letter = 32;
  } else if (handler.letter == 48) {
    handler.letter = 50;
  } else if (handler.letter == 60) {
    handler.letter = 48;
  } else {
    handler.letter++;
  }
  turn = 0xFF;
  Kb_ShowLetter(handle);
  turn = 0x00;
}
